package com.sky.config;

import com.sky.filter.*;
import com.sky.handler.RestfulAccessDeniedHandler;
import com.sky.handler.RestfulAuthenticationEntryPoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.util.ObjectUtils;

import java.util.List;
import java.util.Map;

/**
 * @author 陈烨庆
 * @version 1.0
 */
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    /**
     * 由于前台服务没有动态权限功能，所以要配置 required = false
     */
    @Autowired(required = false)
    private SecurityResourceRoleSource securityResourceRoleSource;

    @Autowired(required = false)
    private DynamicSecurityService dynamicSecurityService;

    /**
     * http相关的配置，包括登入登出、异常处理、会话管理等
     *
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry = http.authorizeRequests();

        // 循环白名单进行放行
        for (String url : ignoredUrlsConfig().getUrls()) {
            registry.antMatchers(url).permitAll();
        }

        // 允许OPTIONS请求 CORS
        registry.antMatchers(HttpMethod.OPTIONS).permitAll();

        // 静态资源权限
        if (securityResourceRoleSource != null) {
            Map<String, List<String>> resourceRole = securityResourceRoleSource.getResourceRole();

            // 循环注册
            for (String resource : resourceRole.keySet()) {
                List<String> roles = resourceRole.get(resource);
                registry.antMatchers(resource).hasAnyAuthority(roles.toArray(new String[roles.size()]));
            }
        }

        // 其他任何请求都需要身份认证
        registry
                // 任何请求
                .anyRequest()
                // 都需要认证
                .authenticated()
                .and()
                // 关闭csrf跨站请求伪造：因为现在使用jwt来实现认证
                .csrf().disable()
                // 禁止session
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                // 自定义权限拒接处理类
                .and()
                .exceptionHandling()
                // 没有权限访问时的处理类
                .accessDeniedHandler(restfulAccessDeniedHandler())
                // 没有登录时的处理类
                .authenticationEntryPoint(restfulAuthenticationEntryPoint())
                .and()
                .addFilterBefore(jwtAuthenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class);

        // 有动态权限配置时添加动态权限校验过滤器
        if (!ObjectUtils.isEmpty(dynamicSecurityService)) {
            registry.and().addFilterBefore(dynamicSecurityFilter(), FilterSecurityInterceptor.class);
        }
    }

    /**
     * 不添加加密方式会报错 新版本无默认方式
     * java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id "null"
     *
     * @return
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return NoOpPasswordEncoder.getInstance();
    }

    // 自定义的Jwt Token过滤器
    @Bean
    public JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter() throws Exception {
        return new JwtAuthenticationTokenFilter();
    }

    @Bean
    public IgnoredUrlsConfig ignoredUrlsConfig() {
        return new IgnoredUrlsConfig();
    }

    /**
     * 没有权限访问时的处理类
     * @return
     */
    @Bean
    public RestfulAccessDeniedHandler restfulAccessDeniedHandler() {
        return new RestfulAccessDeniedHandler();
    }

    /**
     * 没有登录时的处理类
     * @return
     */
    @Bean
    public RestfulAuthenticationEntryPoint restfulAuthenticationEntryPoint() {
        return new RestfulAuthenticationEntryPoint();
    }

//    @Bean
//    public RestfulAuthenticationSuccessHandler restfulAuthenticationSuccessHandler() {
//        return new RestfulAuthenticationSuccessHandler();
//    }

    /**
     * 在FilterSecurityIntercepter前面的自定义过滤器
     * @return
     */
    @ConditionalOnBean(name = "dynamicSecurityService")
    @Bean
    public DynamicSecurityFilter dynamicSecurityFilter() {
        return new DynamicSecurityFilter();
    }


    /**
     * 鉴权
     * @return
     */
    @ConditionalOnBean(name = "dynamicSecurityService")
    @Bean
    public DynamicAccessDecisionManager dynamicAccessDecisionManager() {
        return new DynamicAccessDecisionManager();
    }

    /**
     * 注册角色
     * @return
     */
    @ConditionalOnBean(name = "dynamicSecurityService")
    @Bean
    public DynamicSecurityMetadataSource dynamicSecurityMetadataSource() {
        return new DynamicSecurityMetadataSource();
    }

}